package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.app.state.ScreenshotAppState;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.control.GhostControl;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.shadow.BasicShadowRenderer;
import java.util.ArrayList;
import java.util.Random;

/**
 * @author Xinchro
 */
public class Main extends SimpleApplication implements PhysicsCollisionListener {
    private BulletAppState bulletAppState;
    private Input input;
    public Box playerBox, baseBox;
    public Geometry playerGeom, baseGeom;
    public boolean debug = false;
    Spatial playModel;
    Player player;
    Pet pet, enemyPet;
    BoxCollisionShape playBox;
    GhostControl playGhost;
    BoxCollisionShape baseColBox;
    GhostControl baseGhost;
    boolean petCanMove, petPlayCol;
    boolean petsHitting;
    Pet pet2, pet3;
    BitmapText timeText, playerLoc, petLoc, petPlayColText, enemyTimeText,
	    petEle;
    ArrayList<Pet> enemies, targetEnemies;
    float basePoints;
    boolean dead =false , pause = false;
       
    public static void main(String[] args) {
        Main app = new Main();
	app.setShowSettings(false);
        app.start();
    }
    
    @Override
    public void simpleInitApp() {
	basePoints = 1000.0f;
	bulletAppState = new BulletAppState();
	stateManager.attach(bulletAppState);
//        playerBox = new Box(Vector3f.ZERO, 1, 1, 1);
//        playerGeom = new Geometry("Box", playerBox);
	flyCam.setEnabled(true);
	flyCam.setZoomSpeed(0);
	flyCam.setMoveSpeed(50);
	java.util.logging.Logger.getLogger("").setLevel(java.util.logging.Level.SEVERE);
	cam.setFrustumFar(1000);
        Material playerMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
	playerMat.setColor("Diffuse", ColorRGBA.Red);
	playerMat.setBoolean("UseMaterialColors",true);
//        playerGeom.setMaterial(playerMat);
	
	enemies = new ArrayList<Pet>();
	targetEnemies = new ArrayList<Pet>();
	
	baseBox = new Box(Vector3f.ZERO, 3, 3, 3);
	baseGeom = new Geometry("Box2", baseBox);
	Material baseMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
	baseMat.setColor("Color", ColorRGBA.White);
	baseGeom.setMaterial(baseMat);
	baseColBox = new BoxCollisionShape(new Vector3f(5.0f, 2.0f, 5.0f));
	baseGhost = new GhostControl(baseColBox);
	baseGeom.setName("Base Model");
	baseGeom.addControl(baseGhost);
	bulletAppState.getPhysicsSpace().add(baseGhost);
	
	Material pinkMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
	pinkMat.setBoolean("UseMaterialColors",true);
	pinkMat.setColor("Diffuse", ColorRGBA.Pink);
	
	input =  new Input(getInputManager(), this);
	
		
	pet = new Pet(this, "Fire pet");
	pet.changeColorTo("red");
	pet.setType(new PetType("Fire"));
	pet2 = new Pet(this, "Water pet");
	pet2.changeColorTo("blue");
	pet2.setType(new PetType("Water"));
	pet3 = new Pet(this, "Nature pet");
	pet3.changeColorTo("green");
	pet3.setType(new PetType("Nature"));
	player = new Player(this);
	player.addPet(pet);
	player.addPet(pet2);
	player.addPet(pet3);
	player.setCurPet(player.pets.get(0));	
	
	
	playModel = assetManager.loadModel("Models/player.j3o");
	
	playBox = new BoxCollisionShape(new Vector3f(2.0f, 2.0f, 2.0f));
	playGhost = new GhostControl(playBox);
	playModel.addControl(playGhost);
	bulletAppState.getPhysicsSpace().add(playGhost);
	
	bulletAppState.getPhysicsSpace().addCollisionListener(this);
	
	pet.petModel.setName("Pet Model");
	playModel.setName("Player Model");
	
	pet.petModel.move(0.0f, 0.0f, 3.0f);
	playModel.move(0.0f, 0.0f, 6.0f);
	playModel.setMaterial(playerMat);
	
	rootNode.attachChild(player.getCurPet().petModel);
	rootNode.attachChild(playModel);
	
	Box floorQuad = new Box(210,1, 210);
	Geometry floorPlane = new Geometry("plane", floorQuad);
	Material floorMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
	floorMat.setColor("Diffuse", ColorRGBA.Gray);
	floorPlane.setMaterial(floorMat);
//	(float)Math.PI
//	floorPlane.rotate(0, 10, 0);
	floorPlane.setLocalTranslation(0, -2, 0);

	/** A white, directional light source */ 
	DirectionalLight sun = new DirectionalLight();
	sun.setDirection((new Vector3f(-0.5f, -0.5f, -0.5f)).normalizeLocal());
	sun.setColor(ColorRGBA.White);
	rootNode.addLight(sun); 
	
	DirectionalLight sun2 = new DirectionalLight();
	sun2.setDirection((new Vector3f(0.5f, 0.5f, 0.5f)).normalizeLocal());
	sun2.setColor(ColorRGBA.White);
	rootNode.addLight(sun2); 
	
	BasicShadowRenderer bsr = new BasicShadowRenderer(assetManager, 256);
	bsr.setDirection(new Vector3f(-.5f,-.5f,-.5f).normalizeLocal()); // light direction
	viewPort.addProcessor(bsr);
	rootNode.setShadowMode(RenderQueue.ShadowMode.Cast);

	rootNode.attachChild(floorPlane);
	
	//bulletAppState.getPhysicsSpace().enableDebug(assetManager);
	getCamera().setLocation(new Vector3f(0.0f, 0.0f, 10.0f));
	getCamera().lookAtDirection(Vector3f.UNIT_Z, Vector3f.UNIT_Z);
	
//	NumberHover num1 = new NumberHover(this, assetManager, "Textures/1.png");
	
//	rootNode.attachChild(num1.getPlane());
	rootNode.attachChild(baseGeom);
//        rootNode.attachChild(playerGeom);
	
	
	timeText = new BitmapText(guiFont, false);
	timeText.setSize(guiFont.getCharSet().getRenderedSize());      
	timeText.setColor(ColorRGBA.White);                             
	timeText.setLocalTranslation(300, timeText.getLineHeight(), 0); 
	
	playerLoc = new BitmapText(guiFont, false);
	playerLoc.setSize(guiFont.getCharSet().getRenderedSize());      
	playerLoc.setColor(ColorRGBA.White);                             
	playerLoc.setLocalTranslation(400, playerLoc.getLineHeight(), 0); 
	
	petLoc = new BitmapText(guiFont, false);
	petLoc.setSize(guiFont.getCharSet().getRenderedSize());      
	petLoc.setColor(ColorRGBA.White);                            
	petLoc.setLocalTranslation(400, petLoc.getLineHeight()*2, 0);
	
	petPlayColText = new BitmapText(guiFont, false);
	petPlayColText.setSize(guiFont.getCharSet().getRenderedSize());      
	petPlayColText.setColor(ColorRGBA.White);                            
	petPlayColText.setLocalTranslation(400, petPlayColText.getLineHeight()*3, 0);
	
	enemyTimeText = new BitmapText(guiFont, false);
	enemyTimeText.setSize(guiFont.getCharSet().getRenderedSize());      
	enemyTimeText.setColor(ColorRGBA.White);                            
	enemyTimeText.setLocalTranslation(300, 200, 0);
	
	petEle = new BitmapText(guiFont, false);
	petEle.setSize(guiFont.getCharSet().getRenderedSize());      
	petEle.setColor(ColorRGBA.White);                            
	petEle.setLocalTranslation(400, petPlayColText.getLineHeight()*4, 0);
	petEle.setText(player.getCurPet().getType().getElement());
	
	guiNode.attachChild(petEle);
	guiNode.attachChild(timeText);
	guiNode.attachChild(playerLoc);
	guiNode.attachChild(petLoc);
	guiNode.attachChild(petPlayColText);
	guiNode.attachChild(enemyTimeText);
	
	this.setDisplayFps(false);
	this.setDisplayStatView(false);
	
	for(int i=0;i<7;i++){
	    if(enemies.size()<50){
		spawnNewEnemy();
	    }else{
		System.out.println("Max enemies");
	    }
	}
	
    }
    
    public void resetPet(){
	player.getCurPet().reset(playModel.getWorldTranslation());
    }
    
    public void takeScreenShot(){
	ScreenshotAppState screenShotState = new ScreenshotAppState();
	this.stateManager.attach(screenShotState);
	screenShotState.takeScreenshot();
	screenShotState.setFilePath("");
    }
    
    public Player getPlayer(){
	return player;
    }
    
    public BulletAppState getBulletAppState(){
	return bulletAppState;
    }
    
    public void removePets(){
	rootNode.detachChild(player.getCurPet().petModel);
    }
    
    public void putPet(){
	rootNode.attachChild(player.getCurPet().petModel);
    }

    public float camZoom = -2.2f;
    public CollisionResults results = new CollisionResults();
    
    
    @Override
    public void collision(PhysicsCollisionEvent event){
//	System.out.println(event.getNodeA().getName());
//	System.out.println(event.getNodeB().getName());
	if(!dead || !pause){

	    if(event.getNodeA() == player.getCurPet().petModel && 
		    event.getNodeB() == playModel){
		petPlayCol = true;
		//System.out.println("Player pet hitting");
	    }
    //	if(event.getNodeA() == null || event.getNodeB().getName()==null){
    //	    
    //	}else{
    //	 System.out.println(event.getNodeA().getName() + " " + event.getNodeB().getName());   
    //	}
	    for(int i=0; i<enemies.size(); i++){
		if((event.getNodeB() == baseGeom && 
		    event.getNodeA() == enemies.get(i).petModel) ||
			(event.getNodeA() == baseGeom && 
		    event.getNodeB() == enemies.get(i).petModel)){
		    //System.out.println("Base getting hit");
		    basePoints -= 0.5f;
		    //System.out.println(event.getNodeA().getName() + " " + event.getNodeB().getName());
		}

		if(event.getNodeA() == player.getCurPet().petModel &&
			event.getNodeB() == enemies.get(i).petModel){
		    targetEnemies.clear();
		    petCanMove = true;
		    petPlayCol = false;
		    petsHitting = true;
		    //plz, plz stop piling them on
		    //plz
		    for(int j=0; j<targetEnemies.size(); j++){
			if(!targetEnemies.contains(enemies.get(i))){
			    targetEnemies.add(enemies.get(i));
			}
		    }
		    if(targetEnemies.size()==0){
			targetEnemies.add(enemies.get(i));
		    }
		    //System.out.println("Pets hitting each other");
		}
	    }
	}
    }
    
    public void spawnNewEnemy(){
	enemyPet = new Pet(this, "Enemy pet");
	enemyPet.setEnemy();
	enemyPet.setRandType();
	enemyPet.randomLoc();
	//enemyPet.changeColorTo();
	enemies.add(enemyPet);
	//System.out.println(enemies.size());
	rootNode.attachChild(enemyPet.petModel);
    }
    
    public void checkForDeadEnemies(){
	for(int i=0; i<enemies.size(); i++){
	    Pet temp = enemies.get(i);
	    if(temp.getHealth() <= 0){
		player.addPoint();
		targetEnemies.clear();
		enemies.remove(temp);
		rootNode.detachChild(temp.petModel);
		bulletAppState.getPhysicsSpace().remove(temp.petModel);
		bulletAppState.getPhysicsSpace().remove(temp.petGhost);
		bulletAppState.getPhysicsSpace().remove(temp.petAtkGhost);
	    }
	}
    }
    
    float roundTime = 10.000f;
    float timeLeft = roundTime;
    float enemyTexTL = 0.000f;    
    float petResetCD=2.000f;
    Vector3f petCurLoc, petPrevLoc;
    Random randEn = new Random();
    
    
    @Override
    public void simpleUpdate(float tpf) {
	if(!dead || !pause){
	    if(basePoints <= 0){
		dead = true;
	    }
	    
	    //10 second countdown
	    if(timeLeft > 0.002f){
		timeLeft -=0.001f;
		//System.out.println(timeLeft);
		String time = String.valueOf(timeLeft);
		timeText.setText(time);
	    }else{
		timeText.setText("0");
		for(int i=0;i<randEn.nextInt(10);i++){
		    if(enemies.size()<50){
			basePoints += 100;
			spawnNewEnemy();
		    }else{
			System.out.println("Max enemies");
		    }
		}
		enemyTexTL = 3.000f;
		timeLeft = roundTime;
	    }

	    for(int i=0;i<enemies.size();i++){
		enemies.get(i).petModel.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
		enemies.get(i).petModel.move((Vector3f.ZERO.subtract(enemies.get(i).petModel.getWorldTranslation())).divide(5000.0f));
	    }

	    if(enemyTexTL > 0.002f){
		enemyTimeText.setText("NEXT WAVE");
		enemyTexTL -= 0.001f;
	    }else{
		enemyTimeText.setText("");
	    }

	    checkForDeadEnemies();

	    petCanMove = true;
    //	getCamera().setLocation((playModel.getWorldTranslation().subtract(new Vector3f(0.0f,camZoom, 0.0f))));
    //		.subtract(getCamera().getDirection().add(playModel.getWorldTranslation().mult(new Vector3f(1.0f,0.0f,1.0f)))));
	    getCamera().setLocation(Vector3f.ZERO.add(new Vector3f(0.0f, 10.0f, 0.0f)));
	    getCamera().lookAt(playModel.getWorldTranslation(), Vector3f.UNIT_Y);
	    player.setLoc(playModel.getWorldTranslation().getX(), playModel.getWorldTranslation().getY());
	    player.getCurPet().petModel.lookAt(playModel.getWorldTranslation(), Vector3f.UNIT_Y);
	    playModel.lookAt((getCamera().getDirection().add(playModel.getWorldTranslation())).multLocal(1.0f, 0.0f, 1.0f), Vector3f.UNIT_Y);
	    //player.getCurPet().setLoc(player.getCurPet().petModel.getWorldTranslation().getX(), player.getCurPet().petModel.getWorldTranslation().getY());
	    if(petPlayCol){
		petCanMove = false; 

		//BUG HERE, PLZ HALP
		//System.out.println("Hello, i am annoying");
	    }else{
		petCanMove = true;
	    }
	    if(petCanMove){
		player.getCurPet().petModel.move((playModel.getWorldTranslation().subtract(player.getCurPet().petModel.getWorldTranslation())).divide(200.0f));	
	    }


	    playerLoc.setText("Base HP: " + String.valueOf(basePoints));
    //	playerLoc.setText(playModel.getWorldTranslation().toString());
    //	petLoc.setText(player.getCurPet().petModel.getWorldTranslation().toString());
    //	petPlayColText.setText(String.valueOf(petPlayCol));
	    petPlayColText.setText("Kills: " + String.valueOf(player.points));

	    if(player.getCurPet().petGhost.getOverlappingCount()<=1){
		petPlayCol = false;
		petsHitting = false;
	    }else{
	    }

	    if(DebugMode.debug){
		System.out.println("player model loc: " + playModel.getWorldTranslation());
		System.out.println("pet model loc: " + player.getCurPet().petModel.getWorldTranslation());
	    }

	    if(DebugMode.debug){
		System.out.println("player loc: " + player.getLoc()[0] + " " + player.getLoc()[1]);
		System.out.println("pet loc: " + player.getCurPet().getLoc()[0] + " " + player.getCurPet().getLoc()[1]);
	    }
	    //TODO: add update code
	}
	if(dead){
	    pause = true;
	    enemyTimeText.setText("All your base are belong to us.");
	    baseGeom.scale(.5f, .5f, .5f);
	}
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
    
    public void quit(){
	System.exit(0);
    }

}
